package com.globallogic.javatrainings.sergiiivanov.model;

import java.io.Serializable;

import com.globallogic.javatrainings.sergiiivanov.resources.ErrorCodes;

/**
 * Links collection of {@link Course} to {@link University} and provides basic
 * management of the collection<br>
 * Methods summary: <li>{@link #CoursesManager()} - creates new
 * {@link CoursesManager} <li>{@link #addCource(String, Const.Discipline)} -
 * creates new {@link Course} and adds it into collection <li>
 * {@link #countCources()} - count courses in collection <li>
 * {@link #getCourseByIndex(int)} - returns instance of {@link Course} stored
 * under index <li>{@link #getCourses()} - returns copy of collection <li>
 * {@link #hasDuplicates(String)} - throws {@link UniversityWarning} if course
 * name exists in collection <li>{@link #removeCourse(Course)} - removes
 * {@link Course} from collection
 * 
 * @author Sergey
 * 
 */
public class CoursesManager implements Serializable, NameUniqueObserver {

    private static final long serialVersionUID = 1L;
    private MyArray<Course> courses;

    /**
     * Creates new {@link CoursesManager}.<br>
     * Used in {@link University#University(String)} and links new
     * {@link CoursesManager} to {@link University#courses}
     */
    public CoursesManager() {
        courses = new MyArray<Course>(new Course[0]);
    }

    /**
     * Creates new course and adds it into collection if name is unique.<br>
     * calls {@link #hasDuplicates(String)} to check if name unique
     * 
     * @param newCourseName
     *            - valid course name (not null, not empty, unique)
     * @param newCourseDiscipline
     *            - {@link Const.Discipline} of new course
     * @throws UniversityWarning
     *             when name is not valid
     */
    public void addCource(String newCourseName, Const.Discipline newCourseDiscipline) throws UniversityWarning {
        Course c = new Course();
        c.setManager(this);
        c.setName(newCourseName);
        c.setDiscipline(newCourseDiscipline);
        courses.add(c);
    }

    /**
     * Count courses {@link #addCource(String, Const.Discipline) added} into
     * collection
     * 
     * @return number of courses in collection
     */
    public int countCources() {
        if (courses == null) {
            return 0;
        }
        return courses.size();
    }

    /**
     * Returns {@link Course} stored in collection under provided index
     * 
     * @param index - valid index, 0 <= index < {@link #countCources()}
     * @return {@link Course}
     * @throws UniversityWarning
     *             when index is not valid
     * @see #addCource(String, Const.Discipline)
     * @see #removeCourse(Course)
     */
    public Course getCourseByIndex(int index) throws UniversityWarning, UniversityFailure {
        if (index < 0 || index >= courses.size()) {
            throw new UniversityWarning(ErrorCodes.COURSE_NOT_FOUND);
        }
        return courses.get(index);
    }

    /**
     * Returns {@link MyArray#copy() copy} of courses collection
     * 
     * @return {@link MyArray} of {@link Course}
     */
    public MyArray<Course> getCourses() {
        return courses.copy();
    }

    /**
     * Lookup name within courses in collection and throws
     * {@link UniversityWarning} if found the equal name Part of
     * {@link NameUniqueObserver} mechanics
     * 
     * @param name
     *            name to lookup
     * @throws UniversityWarning
     *             when course with provided name found
     */
    @Override
    public void hasDuplicates(String name) throws UniversityWarning {
        for (Course c : courses) {
            if (name.equals(c.getName())) {
                throw new UniversityWarning(ErrorCodes.COURSE_NAME_NOT_UNIQUE + name);
            }
        }
    }

    /**
     * Removes all links from the course calling {@link Course#removeLinks()}<br>
     * and removes course from the collection
     * 
     * @param c
     *            {@link Course} in collection
     * @throws UniversityWarning
     *             when course not fount in collection
     * @throws UniversityFailure
     *             when application crashes
     */
    public void removeCourse(Course c) throws UniversityFailure, UniversityWarning {
        if (courses.indexOf(c) > -1) {
            c.removeLinks();
            courses.remove(c);
        } else {
            throw new UniversityWarning(ErrorCodes.COURSE_NOT_FOUND);
        }
    }
}
